package yl.hs.bmipfull.service.production.impl;


import com.fasterxml.jackson.core.JsonProcessingException;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import yl.hs.bmipfull.daos.laboratory.IProductCateDao;
import yl.hs.bmipfull.daos.laboratory.IProductOverageDao;
import yl.hs.bmipfull.daos.production.*;
import yl.hs.bmipfull.daos.salemanage.IBuildProjectInfoDao;
import yl.hs.bmipfull.daos.salemanage.ICustomerInfoDao;
import yl.hs.bmipfull.daos.salemanage.ISaleContractDao;
import yl.hs.bmipfull.daos.salemanage.ISaleContractProductsDao;
import yl.hs.bmipfull.daos.system.IUserInfoDao;
import yl.hs.bmipfull.pojo.finance.ShipSettleTemp;
import yl.hs.bmipfull.pojo.laboratory.ProductOverageEntity;
import yl.hs.bmipfull.pojo.production.ProductShipOrderEntity;
import yl.hs.bmipfull.pojo.production.ProductionDispatchLogEntity;
import yl.hs.bmipfull.pojo.production.ProductionLineEntity;
import yl.hs.bmipfull.pojo.production.ProductionTaskEntity;
import yl.hs.bmipfull.pojo.salemanage.BuildProjectInfoEntity;
import yl.hs.bmipfull.pojo.salemanage.CustomerInfoEntity;
import yl.hs.bmipfull.pojo.salemanage.SaleContractEntity;
import yl.hs.bmipfull.pojo.system.UserInfoEntity;
import yl.hs.bmipfull.service.production.IProductShipOrderService;
import yl.hs.bmipfull.utils.*;
import yl.hs.bmipfull.utils.datastate.*;
import yl.hs.bmipfull.viewmodels.LoginUser;
import yl.hs.bmipfull.viewmodels.PageQuery;
import yl.hs.bmipfull.viewmodels.PageResult;
import yl.hs.bmipfull.viewmodels.SubmitModel;
import yl.hs.bmipfull.viewmodels.finance.OrderState;
import yl.hs.bmipfull.viewmodels.finance.ShipOrderReviewModel;
import yl.hs.bmipfull.viewmodels.finance.ShipOrderSignInfoModel;
import yl.hs.bmipfull.viewmodels.host.ProductionLineDeliverInfoVO;
import yl.hs.bmipfull.viewmodels.production.OrderTransModel;
import yl.hs.bmipfull.viewmodels.salemanmage.ConstructionSignModel;
import yl.hs.bmipfull.viewmodels.salemanmage.SetTimeVO;
import yl.hs.bmipfull.viewmodels.salemanmage.TimeGroupVO;

import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.time.*;
import java.util.*;
import java.util.regex.Pattern;

/**
 * 作用:  产品发货单服务层接口实现<br/>
 * 创建时间: 2021年06月21日 10时08分52秒 <br/>
 *
 * @author 谢东
 */
@Service
public class ProductShipOrderServiceImpl extends ProductionBaseService implements IProductShipOrderService {

    @Override
    public Integer restore(String sn, String cause) {
        var order = dao.findBySN(sn);
        order.setState(OrderState.NORMAL.code);
        var result = dao.update(order);
        if (result > 0) {
            writeLog(ActionType.RESTORE, sn, "恢复发货单:" + cause, null, ProductShipOrderEntity.class);
        }
        return result;
    }

    @Override
    public List<ProductShipOrderEntity> queryList(PageQuery pageQuery, String productCateSn) throws Exception {
        pageQuery.checkSortSides(ProductShipOrderEntity.class);
        var filters = SearchFilterEngine.generateQueryList(pageQuery.getFilters(), ProductShipOrderEntity.class);
        List<Integer> states = parseInteger(pageQuery.getQuery().get("states"));

        var glpsCateSN = HsApp.getSystemSet(CK.AggregateTakeoutSN);
        var BetonSysCode = HsApp.getSystemSet(CK.BetonSysCode);
        var list = dao.queryPage(pageQuery.getQuery(), productCateSn, filters, states);
        for (var o : list) {
            if (o.getProductCateSN().equals(glpsCateSN) && o.getState() >= 10) {
                if (o.getShipmentReviewPrice() != null && o.getShipmentReviewPrice().doubleValue() != 0) {
                    o.setPrice(o.getShipmentReviewPrice());
                }
                o.setAmount(o.getShipmentReviewWeight().multiply(o.getPrice()));
            } else if (o.getProductCateSN().equals(BetonSysCode)) {
                if (o.getState() >= 10) {
                    o.setAmount(o.getShipmentReviewQuantity().multiply(o.getPrice()));
                } else {
                    o.setAmount(o.getQuantity().multiply(o.getPrice()));
                }

            } else {
                if (o.getState() >= 10) {
                    o.setAmount(o.getShipmentReviewWeight().multiply(o.getPrice()));
                } else {
                    o.setAmount(o.getNetWeight().multiply(o.getPrice()));
                }
            }
        }
        return list;
    }

    private List<Integer> parseInteger(Object state) {
        List<Integer> states = new ArrayList<>();
        if (state instanceof List<?> sList) {
            for (var s : sList) {
                if (s != null) {
                    states.add(Integer.parseInt(s.toString()));
                }
            }
        }
        return states;
    }


    @Override
    public PageResult<Map<String, Object>> queryPage(PageQuery pageQuery, int rowNum, int page, String productCateSn) throws Exception {
        pageQuery.checkSortSides(ProductShipOrderEntity.class);
        pageQuery.getQuery().put("querySkip", (page - 1) * rowNum);
        pageQuery.getQuery().put("pageSize", rowNum);
        PageResult<Map<String, Object>> result = new PageResult<>(rowNum);
        var filters = SearchFilterEngine.generateQueryList(pageQuery.getFilters(), ProductShipOrderEntity.class);
        ;
        List<Integer> states = parseInteger(pageQuery.getQuery().get("states"));
        result.setRecords(dao.queryCountByCondition(pageQuery.getQuery(), productCateSn, filters, states));
        result.setPage(page);
        var pData = dao.queryPage(pageQuery.getQuery(), productCateSn, filters, states);
        var orderSNList = pData.stream().map(ProductShipOrderEntity::getSn).toList();
        List<ProductOverageEntity> overageList = new ArrayList<>();
        if (orderSNList.size() > 0) {
            overageList.addAll(productOverageDao.queryByOrderSNList(orderSNList));
        }
        var nData = new ArrayList<Map<String, Object>>();
        var glpsCateSN = HsApp.getSystemSet(CK.AggregateTakeoutSN);
        var BetonSysCode = HsApp.getSystemSet(CK.BetonSysCode);
        var cSNList = pData.stream().map(ProductShipOrderEntity::getContractSN).distinct().toList();
        var contractList = new ArrayList<SaleContractEntity>();
        if (cSNList.size() > 0) {
            contractList.addAll(contractDao.queryBylistSn(cSNList));
        }
        for (var o : pData) {
            var cFindOpt = contractList.stream().filter(t -> t.getSn().equals(o.getContractSN())).findFirst();
            if (cFindOpt.isPresent()) {
                var quantity = o.getState() >= 10 ? o.getShipmentReviewQuantity() : o.getQuantity();
                o.setFreightAmount(cFindOpt.get().getOutFreight().multiply(((quantity.compareTo(new BigDecimal(8)) >= 0 ? quantity : new BigDecimal(8)))));
            }
            if (o.getProductCateSN().equals(glpsCateSN) && o.getState() >= 10) {
                if (o.getShipmentReviewPrice() != null && o.getShipmentReviewPrice().doubleValue() != 0) {
                    o.setPrice(o.getShipmentReviewPrice());
                }
                o.setAmount(o.getShipmentReviewWeight().multiply(o.getPrice()));
            } else if (o.getProductCateSN().equals(BetonSysCode)) {
                if (o.getState() >= 10) {
                    o.setAmount(o.getShipmentReviewQuantity().multiply(o.getPrice()));
                } else {
                    o.setAmount(o.getQuantity().multiply(o.getPrice()));
                }

            } else {
                if (o.getState() >= 10) {
                    o.setAmount(o.getShipmentReviewWeight().multiply(o.getPrice()));
                } else {
                    o.setAmount(o.getNetWeight().multiply(o.getPrice()));
                }
            }
            var item = o.toMap();
            var overage = BigDecimal.ZERO;
            var overageOpt = overageList.stream().filter(t -> t.getShipOrderSN().equals(o.getSn())).findFirst();
            if (overageOpt.isPresent()) {
                overage = overageOpt.get().getOverageWeight();
            }
            item.put("money", (o.getPrice().multiply(o.getNetWeight())).setScale(2, RoundingMode.FLOOR));
            item.put("overage", overage);
            nData.add(item);
        }
        result.setData(nData);
        return result;
    }

    @Override
    public ProductShipOrderEntity findBySn(String sn) {
        return dao.findBySN(sn);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public ProductShipOrderEntity saveProductShipOrder(Map<String, Object> model, String sn) throws Exception {
        Integer result;
        ProductShipOrderEntity entity;
        ProductShipOrderEntity data = null;
        if (Tl.isEmpty(sn) || sn.equals("hsxx")) {
            //执行保存
            entity = new ProductShipOrderEntity();
            Tl.getChangeLog(entity, model);
            entity.setPYFieldValue();
            entity.setSn(queryNewSN(ProductShipOrderEntity.class));
            entity.setOrganizationCode(getDepartSN());
            if (entity.getOrderType() == null) {
                entity.setOrderType((short) 0);
            }
            if (entity.getProductTags() == null) {
                entity.setProductTags("");
            }
            if (entity.getAccountProductName() == null) {
                entity.setAccountProductName("");
            }
            if (entity.getAccountProductSN() == null) {
                entity.setAccountProductSN("");
            }
            if (entity.getAccountProductSpec() == null) {
                entity.setAccountProductSpec("");
            }
            if (entity.getBuildPosition() == null) {
                entity.setBuildPosition("");
            }
            if (!Tl.isEmpty(sn)) {
                if (sn.equals("hsxx")) {
                    entity.setOutTime(new Date());
                }
            }
            result = dao.insertNew(entity);
            if (result > 0) {
                data = entity;
                writeLog(ActionType.CREATE, entity.getSn(), "暂存产品发货单信息", Tl.toJson(entity), ProductShipOrderEntity.class);
            }

        } else {
            //执行修改
            entity = findBySn(sn);
            var changeLog = Tl.getChangeLog(entity, model);
            entity.setPYFieldValue();
            entity.setOrganizationCode(getDepartSN());

            var contract = contractDao.findBySN(entity.getContractSN());
            if (contract != null) {
                entity.setFreightAmount(contract.getOutFreight());
                entity.setContractingUnit(contract.getContractingUnit());
                entity.setSalerName(contract.getSalerName());
            }
            if (entity.getOutTime() == null) {
                entity.setOutTime(new Date());
            }
            result = dao.update(entity);
            if (result > 0) {
                data = entity;
                writeLog(ActionType.UPDATE, sn, changeLog, Tl.toJson(entity), ProductShipOrderEntity.class);
                checkProductPrice(entity.getContractSN(), entity.getProductSN(), entity.getProductCate() + "-" + entity.getProductName() + "-" + entity.getProductSpec());
            }
        }
        if (result > 0) {
            saveGS(
                    entity.getSn(),
                    entity.getCustomerName(),
                    String.join(",",
                            entity.getCustomerName(),
                            entity.getProjectName(),
                            entity.getAddress(),
                            entity.getBuildPosition(),
                            entity.getHandlerName(),
                            entity.getLinkerName(),
                            entity.getLinkePhone(),
                            entity.getProductLineName(),
                            entity.getProductName(),
                            entity.getSalePhone(),
                            entity.getSalerName(),
                            entity.getTruckPlate(),
                            entity.getTruckCode(),
                            entity.getRemark()
                    ),
                    entity,
                    HsApp.getCurrent() != null ? HsApp.getCurrent().getUserSN() : null,
                    null
            );
        }
        return data;
    }

    private void checkProductPrice(String contractSN, String productSN, String product) {
        var contract = scDao.findBySN(contractSN);
        if (contract != null && "合同价".equals(contract.getChannel())) {
            var products = scpDao.queryBySaleBSn(contractSN);
            var result = products.stream().filter(t -> productSN.equals(t.getProductSN())).count();
            if (result == 0) {
                try {
                    var setInfo = HsApp.getSystemSet(CK.ContractManagerCode);
                    var toUser = contract.getSalerSN();
                    if (!Tl.isEmpty(setInfo)) {
                        toUser = setInfo;
                    }
                    sendMsg(toUser, "产品价格设置提醒", "合同(" + contractSN + ")【" + contract.getTitle() + "】中缺少" + product);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public Integer delete(String[] sn) {
        Integer result = dao.changeStateBySN(sn, DataState.DELETED.code);
        if (result > 0) {
            writeLog(ActionType.DELETE, sn, ProductShipOrderEntity.class);
            deleteGs(sn);
        }
        return result;
    }

    @Override
    public double getDayVolume(Date date, String productCateSN) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        if (cal.get(Calendar.HOUR_OF_DAY) < 8) {
            Date endTime = Tl.strToDate(Tl.getDateString(date, "yyyy-MM-dd 08:00"));
            cal.add(Calendar.DATE, -1);
            Date startTime = Tl.strToDate(Tl.getDateString(cal.getTime(), "yyyy-MM-dd 08:00"));
            return dao.getTimeRangeVolume(startTime, endTime, productCateSN);
        } else {
            Date startTime = Tl.strToDate(Tl.getDateString(date, "yyyy-MM-dd 08:00"));
            cal.add(Calendar.DATE, 1);
            Date endTime = Tl.strToDate(Tl.getDateString(cal.getTime(), "yyyy-MM-dd 08:00"));
            return dao.getTimeRangeVolume(startTime, endTime, productCateSN);
        }
    }

    @Override
    public double getMonthVolume(Date date, String productCateSN) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        if (cal.get(Calendar.DAY_OF_MONTH) == 1 && cal.get(Calendar.HOUR_OF_DAY) < 8) {
            Date endTime = Tl.strToDate(Tl.getDateString(date, "yyyy-MM-01 08:00"));
            cal.add(Calendar.MONTH, -1);
            Date startTime = Tl.strToDate(Tl.getDateString(cal.getTime(), "yyyy-MM-01 08:00"));
            return dao.getTimeRangeVolume(startTime, endTime, productCateSN);
        } else {
            Date startTime = Tl.strToDate(Tl.getDateString(date, "yyyy-MM-01 08:00"));
            cal.add(Calendar.MONTH, 1);
            Date endTime = Tl.strToDate(Tl.getDateString(cal.getTime(), "yyyy-MM-01 08:00"));
            return dao.getTimeRangeVolume(startTime, endTime, productCateSN);
        }
    }

    @Override
    public double getVolumeByTaskSN(List<String> snArray) {
        return dao.getVolumeByTaskSN(snArray);
    }

    @Override
    public List<ProductShipOrderEntity> findByState(short state, int top, String sort, Object key, String productCateSN) {
        return dao.findByState(state, top, sort, key, productCateSN);
    }

    @Override
    public ProductShipOrderEntity findListByTruckCode(String truckCode) {
        return dao.findListByTruckCode(truckCode);
    }

    @Override
    public List<Map<String, Object>> getListByProductionTaskSN(PageQuery pageQuery) {
        List<ProductShipOrderEntity> shipList = dao.getListByProductionTaskSN(pageQuery.getQuery(), null, null);
        if (pageQuery.getQuery().get("taskSN") == null || "".equals(pageQuery.getQuery().get("taskSN"))) {
            if (shipList.size() > 50) {
                shipList = shipList.subList(0, 50);
            }
        }
        List<Map<String, Object>> shipMap = new ArrayList<>();
        List<ProductionTaskEntity> taskList = new ArrayList<>();
        List<BuildProjectInfoEntity> projectList = new ArrayList<>();
        List<ProductionLineEntity> lineList = new ArrayList<>();
        List<ProductionDispatchLogEntity> logList = new ArrayList<>();
        List<UserInfoEntity> userList = new ArrayList<>();
        if (shipList.size() > 0) {
            var taskSNList = shipList.stream().map(t -> t.getTaskSN()).distinct().toList();
            if (taskSNList.size() > 0) {
                taskList.addAll(taskDao.queryListBySNList(taskSNList));
            }
            var projectSNList = shipList.stream().map(t -> t.getProjectSN()).distinct().toList();
            if (projectSNList.size() > 0) {
                projectList.addAll(projectDao.queryListBySNList(projectSNList));
            }
            var lineSNList = shipList.stream().map(t -> t.getLineSN()).distinct().toList();
            if (lineSNList.size() > 0) {
                lineList.addAll(lineDao.queryListBySNList(lineSNList));
            }
            var orderSNList = shipList.stream().map(t -> t.getSn()).toList();
            logList.addAll(logDao.queryListByMainSN(orderSNList, new short[]{ActionType.CREATE.code, ActionType.UPDATE.code}));
            var userSNList = logList.stream().map(t -> t.getUserSN()).distinct().toList();
            if (userSNList.size() > 0) {
                userList.addAll(userDao.queryByUserSNList(userSNList));
            }
        }
        for (ProductShipOrderEntity entity : shipList) {
            var entityMap = entity.toMap();
            var taskOpt = taskList.stream().filter(t -> t.getSn().equals(entity.getTaskSN())).findFirst();
            entityMap.put("taskEntity", taskOpt.isPresent() ? taskOpt.get() : new ProductionTaskEntity());
            var projectOpt = projectList.stream().filter(t -> t.getSn().equals(entity.getProjectSN())).findFirst();
            entityMap.put("projectEntity", projectOpt.isPresent() ? projectOpt.get() : new BuildProjectInfoEntity());
            var lineOpt = lineList.stream().filter(t -> t.getSn().equals(entity.getLineSN())).findFirst();
            entityMap.put("lineEntity", lineOpt.isPresent() ? lineOpt.get() : new ProductionLineEntity());
            //获取最新修改日志

            //获取最新修改日志
            var upOpt = logList.stream().filter(t -> t.getDataSN().equals(entity.getSn()) && t.getActionType() == ActionType.UPDATE.code).sorted(Comparator.comparing(ProductionDispatchLogEntity::getHandleTime).reversed()).findFirst();
            if (upOpt.isPresent()) {
                var userOpt = userList.stream().filter(t -> t.getSn().equals(upOpt.get().getUserSN())).findFirst();
                entityMap.put("lastAlertUser", userOpt.isPresent() ? userOpt.get().getRealname() : null);
                entityMap.put("lastAlertTime", upOpt.get().getHandleTime());
            } else {
                entityMap.put("lastAlertUser", null);
                entityMap.put("lastAlertTime", null);
            }
            //获取创建数据日志
            var createOpt = logList.stream().filter(t -> t.getDataSN().equals(entity.getSn()) && t.getActionType() == ActionType.CREATE.code)
                    .sorted(Comparator.comparing(ProductionDispatchLogEntity::getHandleTime).reversed()).findFirst();
            if (createOpt.isPresent()) {
                var userOpt = userList.stream().filter(t -> t.getSn().equals(createOpt.get().getUserSN())).findFirst();
                entityMap.put("createUser", userOpt.isPresent() ? userOpt.get().getRealname() : null);
                entityMap.put("createTime", createOpt.get().getHandleTime());
            } else {
                entityMap.put("createUser", null);
                entityMap.put("createTime", null);
            }
            shipMap.add(entityMap);
        }

        return shipMap;
    }

    @Override
    public ProductShipOrderEntity findByOrderType(String productCateSN, String truckCode) {
        return dao.findByOrderType(productCateSN, truckCode);
    }

    @Override
    public ProductShipOrderEntity findByTaskSn(String productCateSN, String taskSN) {
        return dao.findByTaskSn(productCateSN, taskSN);
    }

    @Override
    public List<ProductShipOrderEntity> findByTruckCodeState(String truckCode, short state) {
        return dao.findByTruckCodeState(truckCode, state);
    }

    @Override
    public List<ProductShipOrderEntity> queryByLineSn(String lineSn) {
        return dao.queryByLineSn(lineSn);
    }

    @Override
    public ProductionLineDeliverInfoVO getDeliverInfoByLineSn(String lineSn) {
        List<ProductShipOrderEntity> productShipOrders = this.queryByLineSn(lineSn);
        ProductionLineDeliverInfoVO deliverInfoVO = new ProductionLineDeliverInfoVO();
        if (productShipOrders != null) {
            BigDecimal sumVolume = BigDecimal.ZERO;

            for (ProductShipOrderEntity shipOrder : productShipOrders) {
                sumVolume = sumVolume.add(shipOrder.getQuantity());
            }
            deliverInfoVO.setTrainAmount(productShipOrders.size());
            deliverInfoVO.setVolume(sumVolume);

        }
        return deliverInfoVO;
    }

    @Override
    public List<ProductShipOrderEntity> questListByType(String productCateSN, Date time) {
        return dao.questListByType(productCateSN, time);
    }

    @Override
    public Integer saveReviewOrders(SubmitModel model) {
        var orderSnList = parseString(model.getData().get("orders"));
        if (orderSnList.size() > 0) {
            var user = HsApp.getCurrent();
            var review = false;
            var code = OrderState.NORMAL.code;
            if (model.getData().get("review") != null) {
                review = Boolean.parseBoolean(model.getData().get("review").toString());
            }
            if (review) {
                code = OrderState.REVIEWED.code;
            } else {
                code = OrderState.NORMAL.code;
            }
            var result = dao.updateOrderToReviewed(orderSnList, user != null ? user.getUserSN() : "", user != null ? user.getUserName() : "", review, code);
            if (result > 0) {
                writeOrderLog(review ? ActionType.REVIEWED : ActionType.UNREVIEWED, orderSnList, user, null);
            }
            return result;
        }
        return 0;
    }

    private void writeOrderLog(ActionType action, List<String> orderSNList, LoginUser user, String content) {
        for (String s : orderSNList) {
            var log = new ProductionDispatchLogEntity();
            log.setDataSN(s);
            log.setActionType(action.code);
            log.setTypeCode(getTypeCode(ProductShipOrderEntity.class));
            log.setHandleTime(new Date());
            var typeName = getTypeName(ProductShipOrderEntity.class);
            log.setTypeName(typeName);
            log.setUserSN(user.getUserSN());
            log.setUserName(user.getUserName());
            if (content != null) {
                log.setContent(content);
            } else {
                log.setContent(String.format("%s%s了编号为(%s)的%s信息", user.getUserName(), getActionDesc(action), s, typeName));
            }
            logDao.insertNew(log);
        }
    }

    @Override
    public Integer saveSignInfo(SubmitModel submitModel) throws Exception {
        var order = dao.findBySN(submitModel.getSn());
        if (order != null) {
            var user = HsApp.getCurrent();
            var model = new ShipOrderSignInfoModel();
            Tl.getChangeLog(model, submitModel.getData());
            order.setSigner(user != null ? user.getUserName() : "");
            order.setSignSVG(model.getSignSVG());
            order.setSignedQuantity(model.getSignedQuantity());
            order.setSignedWeight(model.getSignedWeight());
            order.setSigningTime(model.getSigningTime());
            order.setSignWay(model.getSignWay());
            order.setSignPhotoPath(model.getSignPhotoPath());
            order.setSignRemark(model.getRemark());
            var dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
            var logContent = (user != null ? user.getUserName() : "") + "提交了发货单" + order.getSn() + "的签收信息：" + model.getSigner() +
                    "在" + dateFormat.format(model.getSigningTime()) + "通过" + model.getSignWay() + "签收" + model.getSignedWeight() + ",合计(" + model.getSignedQuantity() + ")";
            if (model.getNetWeight() == null) {
                model.setNetWeight(BigDecimal.valueOf(0));
            }
            //var temps = order.getNetWeight().subtract(model.getNetWeight());
            if ((model.getNetWeight() != null && BigDecimal.ZERO.compareTo(model.getNetWeight()) < 0) || (model.getQuantity() != null && BigDecimal.ZERO.compareTo(model.getQuantity()) < 0)) {
                logContent += (user != null ? user.getUserName() : "") + "修改了发货单" + order.getSn() + "的数量，从" + order.getQuantity() +
                        "改为" + model.getQuantity() + ",重量从" + model.getNetWeight() + "改为" + order.getNetWeight() + "，修改原因：" + model.getRemark();
            }
            order.setShipmentReviewRemark(model.getShipmentReviewRemark());
//            order.setShipmentReviewQuantity(model.getQuantity());
//            order.setShipmentReviewWeight(model.getNetWeight());
            // order.setGrossWeight(order.getGrossWeight().subtract(temps));
            order.setShipmentReviewFlag(model.getFlag());


            order.setState(OrderState.SIGED.code);
            var result = dao.update(order);

            if (result > 0) {
                assert user != null;
                var log = getLog(order.getSn(), user);
                log.setUserName(user.getUserName());
                log.setContent(logContent);
                logDao.insertNew(log);
                var overage = productOverageDao.findByShipOrderSn(order.getSn());
                if (overage != null) {
                    overage.setQuantityReturned(order.getQuantityReturned());
                    productOverageDao.update(overage);
                }
            }
            var orderSnList = parseString(submitModel.getData().get("orders"));
            if (orderSnList.size() == 1) {
                order.setShipmentReviewUserName((user != null ? user.getUserName() : ""));
                order.setShipmentReviewUserSN((user != null ? user.getUserSN() : ""));
                order.setShipmentReviewTime(new Date());

                order.setShipmentReviewQuantity(model.getQuantity());
                order.setShipmentReviewWeight(model.getNetWeight());
                order.setShipmentReviewPrice(model.getPrice());
                order.setState(OrderState.REVIEWED.code);
                dao.update(order);
            } else {
                saveReviewOrders(submitModel);
            }
            return result;
        }
        return 0;
    }

    @Override
    public Integer saveReviewFlag(SubmitModel submitModel) throws Exception {
        var order = dao.findBySN(submitModel.getSn());
        if (order != null) {
            var user = HsApp.getCurrent();
            var model = new ShipOrderReviewModel();
            Tl.getChangeLog(model, submitModel.getData());
            assert user != null;
            var logContent = user.getUserName() + "标注了发货单" + order.getSn() + "为" + model.getFlag() + "，" + model.getRemark();
            order.setShipmentReviewFlag(model.getFlag());
            order.setShipmentReviewRemark(model.getRemark());
            var result = dao.update(order);
            if (result > 0) {
                var log = getLog(order.getSn(), user);
                log.setUserName(user.getUserName());
                log.setContent(logContent);
                logDao.insertNew(log);
            }
            return result;
        }
        return 0;
    }

    private ProductionDispatchLogEntity getLog(String mainSN, LoginUser user) {
        var log = new ProductionDispatchLogEntity();
        log.setDataSN(mainSN);
        log.setActionType(ActionType.UPDATE.code);
        log.setTypeCode(getTypeCode(ProductShipOrderEntity.class));
        log.setHandleTime(new Date());
        var typeName = getTypeName(ProductShipOrderEntity.class);
        log.setTypeName(typeName);
        log.setUserSN(user.getUserSN());
        return log;
    }

    @Override
    public Integer invalidOrder(String sn, String cause) {
        var order = dao.findBySN(sn);
        if (order != null) {
            order.setState(OrderState.INVALID.code);
            var result = dao.update(order);
            if (result > 0) {
                var user = HsApp.getCurrent();
                assert user != null;
                var log = getLog(order.getSn(), user);
                log.setContent(user.getUserName() + "作废了发货单：" + sn + ",作废原因：" + cause);
                logDao.insertNew(log);
                try {
                    sendMsg("USER230107000001", "作废单据提醒", user.getUserName() + "作废了发货单：" + sn + ",作废原因：" + cause);
                    sendMsg("USER230104000003", "作废单据提醒", user.getUserName() + "作废了发货单：" + sn + ",作废原因：" + cause);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return result;
        }
        return 0;
    }

    @Override
    public List<ShipSettleTemp> queryByContractSn(String contractSn) {
        return dao.queryByContractSn(contractSn);
    }

    @Override
    public Integer changeStateBySN(String[] snList, short state) {
        int result = dao.changeStateBySN(snList, state);
        if (result > 0) {
            forWriteLog(snList, state);
        }
        return result;
    }

    @Override
    public Integer changeInvoicingStateBySN(String[] snList, short state) {
        return dao.changeInvoicingStateBySN(snList, (short) 1);
    }

    @Override
    public List<TimeGroupVO> getSetTime() {
        List<SetTimeVO> setTimeList = dao.getSetTime();

        return VoUtil.groupTime(setTimeList);
    }

    @Override
    public boolean checkTruckTempOrderExist(String truck) {
        var result = dao.findTruckOrderDraft(truck);
        return result != null;
    }

    @Override
    public PageResult<ProductShipOrderEntity> queryContractOrders(PageQuery query, int rowNum, int page) throws Exception {
        query.checkSortSides(ProductShipOrderEntity.class);
        query.getQuery().put("querySkip", (page - 1) * rowNum);
        query.getQuery().put("pageSize", rowNum);
        PageResult<ProductShipOrderEntity> result = new PageResult<>(rowNum);
        List<Integer> states = parseInteger(query.getQuery().get("states"));
        var snList = getConstructionContractSN();
        if (snList.size() > 0) {
            var glpsCateSN = HsApp.getSystemSet(CK.AggregateTakeoutSN);
            var BetonSysCode = HsApp.getSystemSet(CK.BetonSysCode);
            result.setRecords(dao.queryCountByCustom(query.getQuery(), snList, states, "", null));
            var list = dao.queryDataByCustom(query.getQuery(), snList, states, "", null);
            for (var entity : list) {
                if (entity.getProductCateSN().equals(glpsCateSN) && entity.getState() >= 10) {
                    if (entity.getShipmentReviewPrice().compareTo(BigDecimal.ZERO) != 0) {
                        entity.setPrice(entity.getShipmentReviewPrice());
                    }
                    entity.setAmount(entity.getShipmentReviewWeight().multiply(entity.getPrice()));
                } else if (entity.getProductCateSN().equals(BetonSysCode)) {
                    if (entity.getState() >= 10) {
                        entity.setAmount(entity.getShipmentReviewQuantity().multiply(entity.getPrice()));
                    } else {
                        entity.setAmount(entity.getQuantity().multiply(entity.getPrice()));
                    }

                } else {
                    if (entity.getState() >= 10) {
                        entity.setAmount(entity.getShipmentReviewWeight().multiply(entity.getPrice()));
                    } else {
                        entity.setAmount(entity.getNetWeight().multiply(entity.getPrice()));
                    }
                }
            }
            result.setData(list);
        } else {
            result.setRecords(0);
            result.setData(new ArrayList<>());
        }
        result.setPage(page);
        return result;
    }

    @Override
    public List<ProductShipOrderEntity> queryContractOrdersList(PageQuery query, int rowNum, int page) throws Exception {
        query.checkSortSides(ProductShipOrderEntity.class);
        query.getQuery().put("querySkip", (page - 1) * rowNum);
        query.getQuery().put("pageSize", rowNum);

        var states = parseInteger(query.getQuery().get("states"));
        var snList = getConstructionContractSN();
        var list = dao.queryDataByCustom(query.getQuery(), snList, states, "", null);
        var glpsCateSN = HsApp.getSystemSet(CK.AggregateTakeoutSN);
        var BetonSysCode = HsApp.getSystemSet(CK.BetonSysCode);
        for (var entity : list) {
            if (entity.getProductCateSN().equals(glpsCateSN) && entity.getState() >= 10) {
                if (entity.getShipmentReviewPrice().compareTo(BigDecimal.ZERO) != 0) {
                    entity.setPrice(entity.getShipmentReviewPrice());
                }
                entity.setAmount(entity.getShipmentReviewWeight().multiply(entity.getPrice()));
            } else if (entity.getProductCateSN().equals(BetonSysCode)) {
                if (entity.getState() >= 10) {
                    entity.setAmount(entity.getShipmentReviewQuantity().multiply(entity.getPrice()));
                } else {
                    entity.setAmount(entity.getQuantity().multiply(entity.getPrice()));
                }

            } else {
                if (entity.getState() >= 10) {
                    entity.setAmount(entity.getShipmentReviewWeight().multiply(entity.getPrice()));
                } else {
                    entity.setAmount(entity.getNetWeight().multiply(entity.getPrice()));
                }
            }
        }
        return list;
    }

    @Override
    public Integer queryNotSignedContractOrderCount(PageQuery query) {

        try {
            List<Integer> states = new ArrayList<>();
            List<String> snList = getConstructionContractSN();
            if (snList.size() > 0) {
                states.add(1);
                return dao.queryCountByCustom(query.getQuery(), snList, states, "", null);
            }
            return 0;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

    private CustomerInfoEntity createCustomer(String customerName) throws InvocationTargetException, IllegalAccessException {
        var customer = custDao.findByName(customerName, "");
        if (customer == null) {
            customer = new CustomerInfoEntity();
            customer.setCustName(customerName);
            customer.setSn(queryNewSN(customer.getClass()));
            customer.setOrganizationCode(getDepartSN());
            customer.setPYFieldValue();
            var user = HsApp.getCurrent();
            var result = custDao.insertNew(customer);
            if (result > 0) {
                var shareCode = writeUserTag(customer.getSn(), customer.getClass(), RelationType.CREATE.toString());
                saveGS(
                        customer.getSn(),
                        customer.getCustName(),
                        String.join(",",
                                customer.getCustName(),
                                customer.getAddress(),
                                customer.getArea()
                        ),
                        customer,
                        user != null ? user.getUserSN() : "",
                        shareCode
                );
            }
        }
        return customer;
    }

    private BuildProjectInfoEntity createProject(String projectName, String address, CustomerInfoEntity customer) throws InvocationTargetException, IllegalAccessException {
        BuildProjectInfoEntity entity = projectDao.findByNameAndAddr(projectName, address);
        if (entity == null) {
            entity = new BuildProjectInfoEntity();
            entity.setSn(queryNewSN(entity.getClass()));
            entity.setProjectName(projectName);
            entity.setAddress(address);
            entity.setCustomerName(customer.getCustName());
            entity.setCustomerSN(customer.getSn());
            entity.setOrganizationCode(getDepartSN());
            entity.setPYFieldValue();
            var result = projectDao.insertNew(entity);
            if (result > 0) {
                var shareCode = writeUserTag(entity.getSn(), entity.getClass(), RelationType.CREATE.toString());
                writeLog(ActionType.CREATE, entity.getSn(), "插入客户工地信息信息", Tl.toJson(entity), BuildProjectInfoEntity.class);
                var user = HsApp.getCurrent();
                saveGS(
                        entity.getSn(),
                        entity.getProjectName(),
                        String.join(",",
                                entity.getProjectName(),
                                entity.getAddress(),
                                entity.getArea(),
                                entity.getCustomerName(),
                                entity.getOwnerName(),
                                entity.getSupervision(),
                                entity.getBuildName()
                        ),
                        entity,
                        shareCode,
                        (user != null ? user.getUserSN() : "")
                );
            }
        } else {
            if (Tl.isEmpty(entity.getAddress()) && !Tl.isEmpty(address)) {
                entity.setAddress(address);
                projectDao.update(entity);
            }
        }
        return entity;
    }

    private SaleContractEntity createContract(CustomerInfoEntity cust, BuildProjectInfoEntity project) throws InvocationTargetException, IllegalAccessException {
        SaleContractEntity entity = scDao.findByCustomerSNAndProjectSN(cust.getSn(), project.getSn());
        if (entity == null) {
            entity = new SaleContractEntity();
            entity.setTitle(cust.getCustName());
            entity.setSn(queryNewSN(entity.getClass()));
            entity.setCustomerSN(cust.getSn());
            entity.setCustomerName(cust.getCustName());
            entity.setState(ContractState.Signed.getCode());
            entity.setContractType(ContractType.Public.code);
            entity.setNature(ContractNature.Official.code);
            entity.setSettleInterval((short) 0);
            entity.setOrganizationCode(getDepartSN());
            var user = HsApp.getCurrent();
            entity.setPrintTitle((user != null ? user.getCompanyName() : ""));
            entity.setPYFieldValue();
            var result = scDao.insertNew(entity);
            writeSaleTag(entity.getSn(), entity.getSalerSN(), entity.getSalerName(), null);
            if (result > 0) {
                var shareCode = writeUserTag(entity.getSn(), entity.getClass(), RelationType.CREATE.toString());
                saveGS(
                        entity.getSn(),
                        entity.getTitle(),
                        String.join(",",
                                entity.getTitle(),
                                entity.getCustomerName()
                        ),
                        entity,
                        HsApp.getCurrent() != null ? HsApp.getCurrent().getUserSN() : null,
                        shareCode
                );

                writeLog(ActionType.CREATE, entity.getSn(), "插入销售合同信息信息", Tl.toJson(entity), SaleContractEntity.class);
            }
        }
        return entity;
    }

    @Override
    public ProductShipOrderEntity uploadOrder(SubmitModel submitModel) throws Exception {
        ProductShipOrderEntity entity;
        if (Tl.isEmpty(submitModel.getSn())) {
            entity = new ProductShipOrderEntity();
            Tl.getChangeLog(entity, submitModel.getData());
            var old = dao.findBySN(entity.getSn());
            if (old != null) {
                return old;
            }
            var pCateSn = HsApp.getSystemSet(CK.BetonSysCode);
            var cate = pCateDao.findBySN(pCateSn);

            entity.setProductCate(cate.getCateName());
            entity.setProductCateSN(cate.getSn());
            var customer = createCustomer(entity.getCustomerName());
            entity.setCustomerSN(customer.getSn());
            var project = createProject(entity.getProjectName(), entity.getAddress(), customer);
            entity.setProjectSN(project.getSn());
            var contract = createContract(customer, project);
            entity.setContractSN(contract.getSn());
            entity.setPYFieldValue();
            entity.setOrganizationCode(getDepartSN());

            if (entity.getOrderType() == null) {
                entity.setOrderType((short) 0);
            }
            entity.setState(OrderState.NORMAL.code);
            var result = dao.insertNew(entity);
            sendConstructMessage("车辆" + entity.getTruckCode() + "装载" + entity.getQuantity() + "方[" + entity.getProductName() + "]，单号：" + entity.getSn() + "，已出厂，请等待签收！", entity.getContractSN(), "新的发货单" + entity.getSn());
            if (result > 0) {
                writeLog(ActionType.CREATE, entity.getSn(), "暂存产品发货单信息", Tl.toJson(entity), ProductShipOrderEntity.class);
                saveGS(
                        entity.getSn(),
                        entity.getCustomerName(),
                        String.join(",",
                                entity.getCustomerName(),
                                entity.getProjectName(),
                                entity.getAddress(),
                                entity.getBuildPosition(),
                                entity.getHandlerName(),
                                entity.getLinkerName(),
                                entity.getLinkePhone(),
                                entity.getProductLineName(),
                                entity.getProductName(),
                                entity.getSalePhone(),
                                entity.getSalerName(),
                                entity.getTruckPlate(),
                                entity.getTruckCode(),
                                entity.getRemark()
                        ),
                        entity,
                        HsApp.getCurrent() != null ? HsApp.getCurrent().getUserSN() : null,
                        null
                );
            }
        } else {
            entity = dao.findBySN(submitModel.getSn());
            Tl.getChangeLog(entity, submitModel.getData());
            dao.update(entity);
            if (entity.getState() < 0) {
                deleteGs(new String[]{entity.getSn()});
            }
        }
        return entity;
    }

    @Override
    public ProductShipOrderEntity querySignedOrder(String sn) {
        var entity = dao.findBySN(sn);
        if (entity != null && entity.getState() >= OrderState.SIGED.code) {
            return entity;
        }
        return null;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public ProductShipOrderEntity saveOutWeight(SubmitModel submitModel) throws Exception {
        String sn = submitModel.getSn(),
                taskSn = Tl.getString(submitModel.getData().get("taskSN")),
                cateSN = Tl.getString(submitModel.getData().get("productCateSN"));

        var order = dao.findBySN(sn);
        var changeLog = Tl.getChangeLog(order, submitModel.getData());
        var lastOrder = dao.findByTaskSn(cateSN, taskSn);
        if (lastOrder != null) {
            order.setCumulativeTrucks(lastOrder.getCumulativeTrucks() + 1);
            order.setCumulativeQuantity(lastOrder.getCumulativeQuantity().add(order.getQuantity()));
        }
        order.setPYFieldValue();
        order.setOrganizationCode(getDepartSN());
        var result = dao.update(order);

        if (result > 0) {
            writeLog(ActionType.UPDATE, sn, changeLog, Tl.toJson(order), ProductShipOrderEntity.class);
            checkProductPrice(order.getContractSN(), order.getProductSN(), order.getProductCate() + "-" + order.getProductName() + "-" + order.getProductSpec());
            saveGS(
                    order.getSn(),
                    order.getCustomerName(),
                    String.join(",",
                            order.getCustomerName(),
                            order.getProjectName(),
                            order.getAddress(),
                            order.getBuildPosition(),
                            order.getHandlerName(),
                            order.getLinkerName(),
                            order.getLinkePhone(),
                            order.getProductLineName(),
                            order.getProductName(),
                            order.getSalePhone(),
                            order.getSalerName(),
                            order.getTruckPlate(),
                            order.getTruckCode(),
                            order.getRemark()
                    ),
                    order,
                    HsApp.getCurrent() != null ? HsApp.getCurrent().getUserSN() : null,
                    null
            );
        }
        return order;
    }

    private List<String> parseString(Object s) {
        List<String> sList = new ArrayList<>();
        if (s instanceof List<?> objList) {
            for (var o : objList) {
                sList.add(o.toString());
            }
        }
        return sList;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public Integer saveFreightReviewOrders(SubmitModel model) {
        var orderSnList = parseString(model.getData().get("orders"));
        if (orderSnList.size() > 0) {
            var user = HsApp.getCurrent();
            var review = false;
            if (model.getData().get("review") != null) {
                review = Boolean.parseBoolean(model.getData().get("review").toString());
            }
            var result = dao.updateOrderFreightReviewed(orderSnList, (user != null ? user.getUserSN() : ""), (user != null ? user.getUserName() : ""), review);
            if (result > 0) {
                writeOrderLog(review ? ActionType.REVIEWED : ActionType.UNREVIEWED, orderSnList, user, "完成运费审核");
            }
            return result;
        }
        return 0;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public Integer saveFreightReviewFlag(SubmitModel model) {
        var order = dao.findBySN(model.getSn());
        if (order != null) {
            var user = HsApp.getCurrent();
            var freightAmount = Tl.getBigDecimal(model.getData().get("freightAmount"));
            var turnSiteFreight = Tl.getBigDecimal(model.getData().get("turnSiteFreight"));
            var remark = Tl.getString(model.getData().get("remark"));

            var logContent = (user != null ? user.getUserName() : "") + "标注了发货单" + order.getSn() + "为运费已审核，运费:" + order.getFreightAmount() + "，转工地运费:" + order.getFreightAmount() + ",审核运费:" + order.getFreightAmount() + "，备注" + remark;
            order.setFreightReviewAmount(freightAmount);
            order.setFreightReviewRemark(remark);
            order.setFreightState((short) 1);
            order.setFreightReviewTime(new Date());
            order.setTurnSiteFreight(turnSiteFreight);
            order.setFreightReviewUserName((user != null ? user.getUserName() : ""));
            order.setFreightReviewUserSN((user != null ? user.getUserSN() : ""));
            var result = dao.update(order);
            if (result > 0) {
                assert user != null;
                var log = getLog(order.getSn(), user);
                log.setUserName(user.getUserName());
                log.setContent(logContent);
                logDao.insertNew(log);
            }
            return result;
        }
        return 0;
    }

    @Override
    public Integer updateFiles() {
        List<Map<String, Object>> orders = dao.findOldOrders();
        for (var order : orders) {
            String files = order.get("signPhotoPath").toString();
            List<String> fileList = new ArrayList<>();
            gpFile(files, fileList);
            dao.updateFile(String.join(",", fileList), (long) order.get("id"));
        }
        return orders.size();
    }

    private void gpFile(String file, List<String> files) {
        Pattern r = Pattern.compile("[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}\\.jpg");
        var m = r.matcher(file);
        if (m.find()) {
            var st = m.group();
            files.add(st);
            gpFile(file.replace(st, ""), files);
        }

    }


    @Override
    public Integer saveConstructionSignInfo(ConstructionSignModel model) {
        var order = brickShipOrderDetailDao.findBySN(model.getOrderSN());
        try {
            if (order != null) {
                var user = HsApp.getCurrent();
                order.setSigner((user != null ? user.getUserName() : ""));
                order.setSignedQuantity(model.getSignedQuantity());
                order.setSigningTime(new Date());
                order.setSignSVG(model.getSignSVG());
                order.setSignWay(model.getSignWay());
                order.setSignRemark(model.getSignRemark());
                var dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
                assert user != null;
                var logContent = user.getUserName() + "提交了发货单" + order.getSn() + "的签收信息：" + user.getUserName() +
                        "在" + dateFormat.format(order.getSigningTime()) + "通过" + model.getSignWay() + "签收" + model.getSignedWeight() + ",合计(" + model.getSignedQuantity() + ")";
                order.setState(OrderState.SIGED.code);
                var result = brickShipOrderDetailDao.update(order);
                //sendSysFeatherMessage(user.getUserName() + "已签收" + order.getSn() + ",签收" + order.getSignedQuantity() + "-" + (order.getQuantity().compareTo(order.getSignedQuantity()) == 0 ? "全签" : model.getSignRemark()),
                        //order.getContractSN(), "发货单" + order.getSn() + "已签收");
                if (result > 0) {
                    var beick = brickShipOrderDao.findBySN(order.getOrderSN());
                    if(beick!=null && beick.getState()<=8){
                        beick.setState((short) 8);
                        brickShipOrderDao.update(beick);
                    }
                    var log = getLog(order.getSn(), user);
                    log.setUserName(user.getUserName());
                    log.setContent(logContent);
                    logDao.insertNew(log);
                    //sendMsg(MsgType.System, order.get, "发货单签收提醒", "发货单编号为" + order.getSn() + "已签收。");
                }
                return result;
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return 0;
    }

    @Override
    public Integer saveOrderTrans(OrderTransModel transForm) throws JsonProcessingException {
        var user = HsApp.getCurrent();
        var oldOrder = dao.findBySN(transForm.getOrderSN());
        var backJson = oldOrder.toJson();
        var nTask = taskDao.findBySN(transForm.getTaskSN());
        var newOrder = getNewOrder(oldOrder);
        loadTask(newOrder, nTask);
        if (transForm.getTransWeight().compareTo(oldOrder.getNetWeight()) == 0 || transForm.getTransQuantity().compareTo(oldOrder.getQuantity()) == 0) {
            oldOrder.setState(OrderState.INVALID.code);
            oldOrder.setRemark(oldOrder.getRemark() + "【此单已全部转发新工地】");
        } else {
            if (oldOrder.getDensity().compareTo(newOrder.getDensity()) != 0 || oldOrder.getAppendWeight().compareTo(BigDecimal.ZERO) > 0) {
                var tempDensity = oldOrder.getNetWeight().divide(oldOrder.getQuantity(), RoundingMode.FLOOR);
                var weight = transForm.getTransQuantity().multiply(tempDensity);
                oldOrder.setGrossWeight(oldOrder.getGrossWeight().subtract(weight));
                oldOrder.setNetWeight(oldOrder.getNetWeight().subtract(weight));
                newOrder.setNetWeight(weight);
                newOrder.setQuantity(transForm.getTransQuantity());
                newOrder.setGrossWeight(newOrder.getTareWeight().add(weight));
            } else {
                oldOrder.setQuantity(oldOrder.getQuantity().subtract(transForm.getTransQuantity()));
                oldOrder.setNetWeight(oldOrder.getNetWeight().subtract(transForm.getTransWeight()));
                newOrder.setNetWeight(transForm.getTransWeight());
                newOrder.setQuantity(transForm.getTransQuantity());
            }
            newOrder.setRemark(String.format("【从发货单%s转工地操作单据】，", oldOrder.getSn()) + transForm.getRemark());
        }
        var last = dao.findByTaskSn(newOrder.getProductCateSN(), newOrder.getTaskSN());
        if (last != null) {
            newOrder.setCumulativeQuantity(last.getCumulativeQuantity().add(newOrder.getQuantity()));
            newOrder.setCumulativeTrucks(last.getCumulativeTrucks() + 1);
        } else {
            newOrder.setCumulativeQuantity(newOrder.getQuantity());
            newOrder.setCumulativeTrucks(1);
        }
        newOrder.setAccountProductName(nTask.getAccountProductName());
        newOrder.setAccountProductSN(nTask.getAccountProductSN());
        newOrder.setAccountProductSpec(nTask.getAccountProductSpec());
        newOrder.setBillProductSN(nTask.getBillProductSN());
        newOrder.setBillProductName(nTask.getBillProductName());
        newOrder.setBillProductSpec(nTask.getBillProductSpec());
        dao.update(oldOrder);
        dao.insertNew(newOrder);
        writeLog(ActionType.UPDATE, oldOrder.getSn(), "转工地到" + newOrder.getProjectName() + ",新单号：" + newOrder.getSn(), backJson, ProductShipOrderEntity.class);
        writeLog(ActionType.CREATE, newOrder.getSn(), "从发货单" + oldOrder.getSn() + "转工地创建", null, ProductShipOrderEntity.class);
        try {
            sendMsg("USER230107000001", "转工地提醒", user.getUserName() + "执行了转工地操作,将编号为" + oldOrder.getSn() + "，工程名称为" + oldOrder.getProjectName() + "的发货单，转发为编号为" + newOrder.getSn() + "，工程名称为" + newOrder.getProjectName() + "的发货单");
            sendMsg("USER230104000003", "转工地提醒", user.getUserName() + "执行了转工地操作,将编号为" + oldOrder.getSn() + "，工程名称为" + oldOrder.getProjectName() + "的发货单，转发为编号为" + newOrder.getSn() + "，工程名称为" + newOrder.getProjectName() + "的发货单");
        } catch (Exception e) {
            e.printStackTrace();
        }

        return 2;
    }


    private ProductShipOrderEntity getNewOrder(ProductShipOrderEntity o) {
        var n = new ProductShipOrderEntity();
        n.setSn(queryNewSN(ProductShipOrderEntity.class));
        n.setOrderType(o.getOrderType());
        n.setTruckSN(o.getTruckSN());
        n.setTruckCode(o.getTruckCode());
        n.setTruckPlate(o.getTruckPlate());
        n.setTareWeight(o.getTareWeight());
        n.setOrgTareWeight(o.getOrgTareWeight());
        n.setGrossWeight(o.getGrossWeight());
        n.setAppendWeight(o.getAppendWeight());
        n.setSalesVolume(o.getSalesVolume());
        n.setProductName(o.getProductName());
        n.setOrgGrossWeight(o.getOrgGrossWeight());
        n.setQuantity(o.getQuantity());
        n.setNetWeight(o.getNetWeight());
        n.setUnitName(o.getUnitName());
        n.setPackWeight(o.getPackWeight());
        n.setPackWay(o.getPackWay());
        n.setPackUnit(o.getPackUnit());
        n.setHandlerSN(o.getHandlerSN());
        n.setHandlerName(o.getHandlerName());
        n.setPrintWay(o.getPrintWay());
        n.setMergeSN(o.getMergeSN());
        n.setOutTime(o.getOutTime());
        n.setOrganizationCode(o.getOrganizationCode());
        n.setLineSN(o.getLineSN());
        n.setDriverSN(o.getDriverSN());
        n.setDriverName(o.getDriverName());
        n.setPrintTitle(o.getPrintTitle());
        n.setBackTime(o.getBackTime());
        n.setBackWeight(o.getBackWeight());
        n.setProductLineName(o.getProductLineName());
        n.setProductSN(o.getProductSN());
        n.setProductCate(o.getProductCate());
        n.setProductCateSN(o.getProductCateSN());
        n.setProductSpec(o.getProductSpec());
        n.setState(o.getState());

        return n;
    }

    private void loadTask(ProductShipOrderEntity o, ProductionTaskEntity t) {
        o.setTaskSN(t.getSn());
        o.setContractSN(t.getContractSN());
        var contract = contractDao.findBySN(t.getContractSN());
        o.setCustomerSN(contract.getCustomerSN());
        o.setCustomerName(t.getCustomName());
        o.setBuildPosition(t.getPosition());

        o.setProjectSN(t.getProductSN());
        o.setProjectName(t.getProjectName());
        o.setProductTags(t.getProductionParam());
        o.setLineSN(t.getProjectLinkerSN());
        o.setLinkerName(t.getProjectLinker());
        o.setLinkePhone(t.getProjectPhone());
        o.setAddress(t.getProjectAddr());
        o.setSalerName(t.getSalerName());
        o.setSalePhone(t.getSalerPhone());
        o.setDensity(t.getDensity());
        o.setContractingUnit(contract.getContractingUnit());
    }


    private Date convertDate(LocalDateTime localDateTime) {
        // 将此日期时间与时区相结合以创建 ZonedDateTime
        ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.systemDefault());
        // 本地时间线LocalDateTime到即时时间线Instant时间戳
        Instant instant = zonedDateTime.toInstant();
        // UTC时间(世界协调时间,UTC + 00:00)转北京(北京,UTC + 8:00)时间
        return Date.from(instant);
    }


    @Override
    public List<String> weightStatistics(Integer type, String companyName, String year, String month) {
        List<String> resultList = Lists.newArrayList();
        // 日统计报表
        if (1 == type) {
            for (int dayIndex = 1; dayIndex <= DateUtil.getMaxDays(year, month); dayIndex++) {
                LocalDateTime startDate = LocalDateTime.of(Integer.valueOf(year), Integer.valueOf(month), dayIndex, 8, 0, 0, 0);
                LocalDateTime endDate = startDate.plusHours(24);
                resultList.add(dao.weightStatisticsByDay(convertDate(startDate), convertDate(endDate), companyName));
            }
        }
        // 月统计报表
        if (2 == type) {
            for (int monthIndex = 1; monthIndex <= 12; monthIndex++) {
                LocalDateTime startDate = LocalDateTime.of(Integer.valueOf(year), monthIndex, 1, 8, 0, 0, 0);
                LocalDateTime endDate = startDate.plusMonths(1);
                resultList.add(dao.weightStatisticsByDay(convertDate(startDate), convertDate(endDate), companyName));
            }
        }
        // 近五年统计报表
        if (3 == type) {
            for (int yearIndex = -1; yearIndex >= -5; yearIndex--) {
                // 最近五年的年份值
                LocalDateTime startDate = LocalDateTime.of(Integer.valueOf(year) + 1, 1, 1, 8, 0, 0, 0);
                LocalDateTime endDate = startDate.plusYears(yearIndex);
                startDate = endDate.plusYears(1);
                resultList.add(dao.weightStatisticsByDay(convertDate(endDate), convertDate(startDate), companyName));
            }
        }
        return resultList;
    }

    public static void main(String[] args) {
        int year = 2023;
        for (int monthIndex = 1; monthIndex <= 12; monthIndex++) {
            String startStr = String.valueOf(year) + "-" + (monthIndex < 10 ? "0" : "") + monthIndex + "-01" + " 08:00:00";
            System.out.println(startStr);
        }
    }

    /**
     * 车辆工地方量统计日报表
     *
     * @param companyName
     * @param startDate
     * @param endDate
     * @return
     */
    @Override
    public Map<String, Object> projectAndCarOrderStatistics(String companyName, Date startDate, Date endDate) {
        Map<String, Object> result = Maps.newLinkedHashMap();
        // 获取时间段内所有运输工地及运输车辆
        ProductShipOrderEntity orderData = dao.getAllProjectsAndTruckCodesByDate(companyName, startDate, endDate);
        if (orderData == null) {
            return null;
        }
        // 格式化titleLists
        List<String> titleList = formatTitleList(orderData.getProjectName().split(","));
        List<String> truckCodes = Arrays.asList(orderData.getTruckCode().split(","));

        // 表单数据
        List<Map<String, String>> truckFormData = Lists.newArrayList();
        // 循环填充车辆运输数据
        for (int truckCodeIndex = 0; truckCodeIndex < truckCodes.size(); truckCodeIndex++) {

            String truckCode = truckCodes.get(truckCodeIndex);
            if (StringUtils.isEmpty(truckCode.trim())) {
                continue;
            }

            Map<String, String> truckData = Maps.newHashMap();
            BigDecimal netWeightAmount = BigDecimal.ZERO;
            for (int titleIndex = 0; titleIndex < titleList.size(); titleIndex++) {
                String title = titleList.get(titleIndex);

                if (StringUtils.isEmpty(truckCode.trim())) {
                    continue;
                }

                // （第一列）车次
                if (titleIndex == 0) {
                    truckData.put(title, truckCode);
                    continue;
                }
                // （中间工地列）车辆对应工程发货量查询
                String netWeight = dao.queryWeightCountByCarAndProjectAndDate(companyName, truckCode, title, startDate, endDate);
                truckData.put(title, netWeight);

                // （最后一列）行发货量合计
                netWeightAmount = netWeightAmount.add(netWeight == null ? BigDecimal.ZERO : new BigDecimal(netWeight));
                if (titleIndex + 1 == titleList.size()) {
                    truckData.put(title, netWeightAmount.toString());
                }

            }
            // 当前车辆工地运输数据
            truckFormData.add(truckData);
        }

        // (最后一行)添加列发货量合计
        for (int index = 0; index < titleList.size(); index++) {
            // 车号列不统计
            if (index == 0) {
                continue;
            }
            Map<String, String> truckData = Maps.newHashMap();
            String title = titleList.get(index);
            // 统计各工地运输量合计
            BigDecimal columnNetWeightAmount = truckFormData.stream().map(o -> format(o.get(title))).reduce(BigDecimal.ZERO, BigDecimal::add);
            truckData.put(title, columnNetWeightAmount.toString());
        }

        result.put("titles", titleList);
        result.put("formData", truckFormData);
        return result;
    }

    /**
     * （表头格式化）
     *
     * @param paramArr
     * @return
     */
    List<String> formatTitleList(String[] paramArr) {
        List<String> titleList = Lists.newArrayList();
        titleList.add("车号");
        for (String title : paramArr) {
            titleList.add(title);
        }
        titleList.add("合计");
        return titleList;
    }

    /**
     * 字符串格式化decimal
     *
     * @param paramDecimal
     * @return
     */
    private BigDecimal format(String paramDecimal) {
        if (StringUtils.isEmpty(paramDecimal)) {
            return BigDecimal.ZERO;
        }
        return new BigDecimal(paramDecimal);
    }


    @Autowired
    public void setDao(IProductShipOrderDao dao) {
        this.dao = dao;
    }

    @Autowired
    public void setLineDao(IProductionLineDao lineDao) {
        this.lineDao = lineDao;
    }

    @Autowired
    public void setContractDao(ISaleContractDao contractDao) {
        this.contractDao = contractDao;
    }

    @Autowired
    public void setTaskDao(IProductionTaskDao taskDao) {
        this.taskDao = taskDao;
    }

    @Autowired
    public void setLogDao(IProductionDispatchLogDao logDao) {
        this.logDao = logDao;
    }

    @Autowired
    public void setCustDao(ICustomerInfoDao custDao) {
        this.custDao = custDao;
    }

    @Autowired
    public void setpCateDao(IProductCateDao pCateDao) {
        this.pCateDao = pCateDao;
    }

    @Autowired
    public void setProductOverageDao(IProductOverageDao productOverageDao) {
        this.productOverageDao = productOverageDao;
    }

    @Autowired
    public void setProjectDao(IBuildProjectInfoDao projectDao) {
        this.projectDao = projectDao;
    }

    @Autowired
    public void setScDao(ISaleContractDao scDao) {
        this.scDao = scDao;
    }

    @Autowired
    public void setScpDao(ISaleContractProductsDao scpDao) {
        this.scpDao = scpDao;
    }

    @Autowired
    public void setUserDao(IUserInfoDao userDao) {
        this.userDao = userDao;
    }
    @Autowired
    IBrickShipOrderDetailDao brickShipOrderDetailDao;
    @Autowired
    IBrickShipOrderDao brickShipOrderDao;
    private IProductShipOrderDao dao;
    private IUserInfoDao userDao;
    private IProductionTaskDao taskDao;
    private IProductionDispatchLogDao logDao;
    private IProductionLineDao lineDao;
    private IBuildProjectInfoDao projectDao;
    private IProductOverageDao productOverageDao;
    private ISaleContractProductsDao scpDao;
    private ISaleContractDao scDao;
    private IProductCateDao pCateDao;
    private ICustomerInfoDao custDao;
    private ISaleContractDao contractDao;
}